<template>
  <view class="mxp-search" :class="cusClass" :style="[cusStyle, { height }]" @click="onSearchView">
    <view class="search-view" :style="[newSearchViewStyle, searchViewStyle]">
      <slot name="prefix">
        <mxp-icon :size="searchIconSize" name="sousuo" :color="searchIconColor || color || defThemeColor.text3" @click.stop.prevent="searchIcon"></mxp-icon>
      </slot>
      <input
        v-if="!disabled"
        confirmType="search"
        :value="data.keyword"
        :disabled="disabled"
        :focus="focus"
        class="input"
        :maxlength="maxlength"
        :placeholder="placeholder"
        :placeholderStyle="`color: ${placeholderColor || defThemeColor.placeholder}`"
        type="text"
        :style="[inputStyle, { textAlign: inputAlign, color: color || defThemeColor.text, background: background || 'transparent', height: inputHeight }]"
        @blur="onBlur"
        @confirm="onConfirm"
        @input="onInput"
        @focus="onFocus"
      />
      <view
        v-else
        key="view-1"
        class="input"
        style="display: flex; align-items: center; justify-content: flex-start; width: 100%"
        :style="[
          {
            color: placeholderColor || defThemeColor.placeholder,
            background: background || 'transparent',
            height: inputHeight,
            justifyContent: inputAlign === 'left' ? 'flex-start' : inputAlign === 'right' ? 'flex-end' : 'center',
          },
        ]"
      >
        <text :style="[{ color: placeholderColor || defThemeColor.placeholder }]">{{ placeholder }}</text>
      </view>
      <view v-if="!disabled && data.keyword && clearable" key="view-2" class="close" @click.stop.prevent="onClear">
        <mxp-icon name="guanbi1" :color="clearIconColor" :size="clearIconSize"></mxp-icon>
      </view>
      <slot name="suffix"></slot>
    </view>
    <text v-if="rightButtonText" :style="newRightButtonStyle" class="right-text" @click.stop.prevent="rightTextClick">
      {{ rightButtonText }}
    </text>
  </view>
</template>

<script lang="ts" setup>
  import mxpIcon from '../mxp-icon/mxp-icon.vue';
  import { type CSSProperties, type PropType, computed, onBeforeMount, shallowReactive, watch } from 'vue';
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import { getXPNumber } from '../mxp-tool/utils/dom';
  import type { InputOnConfirmEvent, InputOnInputEvent } from 'mxp-uni-types';
  import { defThemeColor } from '../mxp-tool/theme/theme';
  defineOptions({
    name: 'mxp-search',
  });

  const props = defineProps({
    /** 绑定值 */
    modelValue: { type: [String, Number], default: '' },
    /** 搜索框形状，round-圆形，square-方形 */
    shape: { type: String as PropType<'round' | 'square'>, default: 'round' },
    /** 搜索框背景 */
    background: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 占位提示文字 */
    placeholder: { type: String, default: '请输入搜索内容' },
    /** 是否显示清理按钮 */
    clearable: { type: Boolean, default: true },
    /** 清除按钮的样式 （如设置字体颜色字体大小等） */
    clearIconStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 点击清除按钮是否触发 confirm 件 */
    clearConfirm: { type: Boolean, default: true },
    /** 是否自动聚焦 */
    focus: { type: Boolean, default: false },
    /** 右侧按钮文字传空字符串则不显示，默认为'确定’ */
    rightButtonText: { type: String, default: '确定' },
    /** 是否只在输入框聚焦是才显示rightText */
    isFocusRightButton: { type: Boolean, default: true },
    /** 右侧文本的宽度 （主要用于动画） */
    rightButtonWidth: { type: String as PropType<$SizeUnitStr>, default: '42px' },
    /** 右侧按钮文字的样式 （不建议在这里设置宽度，请在rightTextWidth中设置宽度） */
    rightButtonStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 输入框内容对齐方式，可选值为 left|center|right */
    inputAlign: { type: String as PropType<'center' | 'left' | 'right'>, default: 'left' },
    /** input输入框的样式，可以定义文字颜色，大小等，对象形式 */
    inputStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /**是否禁用输入框 */
    disabled: { type: Boolean, default: false },
    /** 边框颜色，默认为背景色 */
    borderColor: { type: [Boolean, String] as PropType<$AllColorStr | boolean>, default: undefined },
    /** 搜索图标的颜色，默认同输入框字体颜色 */
    searchIconColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 输入框字体颜色 */
    color: { type: String as PropType<$AllColorStr>, default: undefined },
    /** placeholder的颜色 */
    placeholderColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 搜索图标的大小，单位px */
    searchIconSize: { type: String as PropType<$SizeUnitStr>, default: '16px' },
    /** 输入框最大能输入的长度，-1为不限制长度 */
    maxlength: { type: Number, default: -1 },
    /** 搜索框高度，单位px */
    height: { type: String as PropType<$SizeUnitStr>, default: '40px' },
    /** 自定义搜索容器样式 */
    searchViewStyle: { type: Object as PropType<CSSProperties>, default: () => ({}) },
    /** 自定义右侧按钮的操作,当为 false，时点击右侧按钮将触发 rightButtonClick 事件，而不是 confirm 事件，用于配合，修改 rightButtonText 的自定义点击事件 */
    customRightButtonAction: { type: Boolean, default: false },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 搜索框前缀 */
    prefix: () => void;
    /** 搜索框后缀 */
    suffix: () => void;
  }>();

  const emits = defineEmits<{
    (e: 'click'): void;
    (e: 'update:modelValue', str: string): void;
    (e: 'rightButtonClick', str: string): void;
    (e: 'clear', str: string): void;
    (e: 'change', str: string): void;
    (e: 'confirm', str: string): void;
    (e: 'focus', str: string): void;
    (e: 'blur', str: string): void;
    (e: 'clickIcon'): void;
  }>();

  const data = shallowReactive({
    keyword: '',
    isAnimation: false,
  });
  /** 输入框高度为组件高度减去边框高度 */
  const inputHeight = computed(() => `${getXPNumber(props.height || '34px', 34) - 2}px`);

  const clearIconSize = computed(() => (props.clearIconStyle.fontSize || props.clearIconStyle['font-size'] || '16px') as $SizeUnitStr);
  const clearIconColor = computed(() => (props.clearIconStyle.color || defThemeColor.value.icon) as $AllColorStr);

  const newRightButtonStyle = computed<CSSProperties>(() => {
    if ((!props.isFocusRightButton && props.rightButtonText) || data.isAnimation) {
      return { color: defThemeColor.value.primary, width: props.rightButtonWidth || '48px', marginLeft: '4px', marginRight: '4px', ...props.rightButtonStyle };
    } else {
      return { color: defThemeColor.value.primary, width: '0px', marginLeft: '0', marginRight: '0px', ...props.rightButtonStyle };
    }
  });

  const newSearchViewStyle = computed<CSSProperties>(() => {
    return {
      backgroundColor: props.background || defThemeColor.value.fill3,
      borderRadius: props.shape === 'round' ? '9999px' : '4px',
      borderColor:
        typeof props.borderColor === 'string'
          ? props.borderColor
          : props.borderColor === true
            ? defThemeColor.value.border
            : props.background || defThemeColor.value.fill3,
    };
  });

  watch(
    () => props.modelValue,
    (val) => {
      data.keyword = String(val);
    }
  );

  onBeforeMount(() => {
    data.keyword = String(props.modelValue);
  });
  /** 发送事件 */
  function emitsChange() {
    emits('update:modelValue', data.keyword);
    emits('change', data.keyword);
  }

  /** j监听输入框内容变化 */
  function onInput(event: InputOnInputEvent) {
    data.keyword = event.detail.value;
    emitsChange();
  }
  /** 清除输入框内容 */
  function onClear() {
    data.keyword = '';
    emits('clear', '');
    emitsChange();
    if (props.clearConfirm) {
      emits('confirm', data.keyword);
    }
  }

  /** 键盘上的确定按钮点击事件 */
  function onConfirm(event: InputOnConfirmEvent) {
    if ('isComposing' in event && event.isComposing) {
      // 解决监听回车键中文状态下回车选择中文时也触发提交
      return;
    }
    emits('confirm', event.detail.value);
    try {
      uni.hideKeyboard();
    } catch (e) {}
  }

  /** 点击右边自定义按钮的事件 */
  function rightTextClick() {
    if (props.customRightButtonAction) {
      emits('rightButtonClick', data.keyword);
    } else {
      emits('confirm', data.keyword);
    }
    try {
      uni.hideKeyboard();
    } catch (e) {}
  }

  /** 获取焦点 */
  function onFocus() {
    if (props.isFocusRightButton && props.rightButtonText) {
      data.isAnimation = true;
    }
    emits('focus', data.keyword);
  }

  /** 失去焦点 */
  function onBlur() {
    data.isAnimation = false;
    emits('blur', data.keyword);
  }

  /** 点击搜索框，只有disabled=true时才发出事件，因为禁止了输入，意味着是想跳转真正的搜索页 */
  function onSearchView() {
    if (props.disabled) {
      emits('click');
    }
  }

  /** 点击搜索图标 */
  function searchIcon() {
    emits('clickIcon');
  }
</script>

<style lang="scss" scoped>
  // #ifdef H5
  [type='search']::-webkit-search-decoration {
    display: none;
  }
  // #endif

  .mxp-search {
    display: flex;
    flex-direction: row;
    align-items: center;
    justify-content: flex-start;

    .search-view {
      display: flex;
      flex: 1;
      flex-direction: row;
      align-items: center;
      justify-content: space-between;
      padding: 0 15px;
      overflow: hidden;
      border-style: solid;
      border-width: 1px;

      .input {
        flex: 1;
        margin: 0 15px 0 5px;
        font-size: 14px;
        line-height: 1;
      }

      .close {
        padding: 4px;
        border-radius: 20px;
      }
    }

    .right-text {
      width: 0;
      overflow: hidden;
      font-size: 14px;
      text-align: center;
      white-space: nowrap;
      transition-duration: 0.3s;
      transition-property: width;
    }
  }
</style>
